/*
  ---[PARI/GP]-----------------------------------------------
  
    A215940 and another bases distinct than decimal.
    
  -----------------------------------------------------------
  
  Released under the terms of use for the:
  "On Line Encyclopedia of Integer Sequences OEIS(TM)"

  THIS PROGRAM COMES WITHOUT ANY WARRANTY WHATSOEVER.
  
  Current script written by: Remy Cano. Jan 22 2013
                            (slackgorithmus@gmail.com,
                            http://oeis.org/wiki/User:R._J._Cano)
                
  Purpose: Research about the invariant quotients and A215940.
  
  
  Original contribution written by: Joerg Arndt. Dec 2012
                                    (www.jjj.de)
  
  Purpose: Demonstrative script illustrating the generation of the sequence A055881,
           and its use for computing permutations without repetitions. 

 Note:
 
 1) It works properly for the first bases between binary and decimal.
    However, for another bases greater than 10, it appears to be necessary modify
    the program including some partition scheme for the permutations devised in a
    way that the PARI/GP can support. It is suggested to take advantage from the
    factorial nature of the enumeration for permutations splitting the sets in
    smaller subsets each one of 10! elements in size. Make it at your own risk.
    
 2) It might has been included with the present program additional code for routines
    that are not used in the current version but might be useful for the users.
 
###################################################################################
## WARNING: Remember always to have allocated enough memory for your task either ##
## using "-s PARISTACKSIZE" in the invocation or allocatemem();                  ##
################################################################################### 

Example:
  You might use "clear; gp -q -s 966367642 theprogram.gp" or similar in a Linux shell.
 
*/


/*.........................[User changes begins here]................................*/

assumedBase=10;                        /* Try out for a little base by default. */
\\permutationsUpperBound=assumedBase;    /* The same that assumedBase by default  */
permutationsUpperBound=4;
default(echo,0);

/*
  ............... Each time you run this script for a different base or radix,
  ............... change this setting. It is essentially the unique modification
  ............... nedeed.

...........................[User changes ends here]..................................*/

/*Global*/ P=vector(permutationsUpperBound!);

greatestPermutationNonZeroDigits(r)=sum(k=1,r-1,k*r^(k-1)); \\ Warning: Digit Zero '0' is excluded at purpose and by definition.

smallestPermutationNonZeroDigits(r)=sum(k=1,r-1,k*r^(r-(k+1))); \\ Warning: Digit Zero... ^

povolotskyFraction(r)=(smallestPermutationNonZeroDigits(r)/greatestPermutationNonZeroDigits(r)); \\ Warning: Digit Zero... ^^

reportPovolotskyPairs()={
print("\tLoading permutations...");
/*Every permutation should be translated to decimal by the proper polynomial representation. Please see the proof at A215940.*/
h=povolotskyFraction(assumedBase);
print("\tPerforming calculations...");
Q=P*h;
kount=0;
print("\tReporting the pairs:");
for(u=1,#P,if(denominator(Q[u])==1,kount++;print(kount,") {",P[u],",",Q[u],"};")));
};

permutations(n)=
/*
 * Compute the first n! terms of A055881 by counting in rising factorial base.
 * Generate all permutations of n along the way.
*/
{
    my( fc=vector(n), ct=0, j, a=0, p=vector(n,k,k-1), k, t, S=0 );
    
    while ( 1,
        P[S++]=sum(tau=1,#p,p[tau]*assumedBase^(#p-tau));
        j = 1;
        while ( fc[j] == j,  fc[j]=0;  j+=1; );
        if ( j==n,  return() );
        fc[j] += 1; 
        a = j;
        j += 1;  k = 1;
        while ( k < j,
            t=p[j]; p[j]=p[k]; p[k]=t;
            k+=1; j-=1;
        );
    );
}

povolotskyPrimalityWeakUp(r)=isprime(numerator(povolotskyFraction(r)));

povolotskyPrimalityWeakDown(r)=isprime(denominator(povolotskyFraction(r)));

povolotskyFracHasPrimes(r)={
x=povolotskyFraction(r);
y=( isprime(numerator(x)) || isprime(denominator(x)) );
};

povolotskyPrimalityStrong(r)={
x=povolotskyFraction(r);
y=( isprime(numerator(x)) && isprime(denominator(x)) );
};

/*
    Changes operand1 from decimal (assumed) into another base operand2
*/

/* Justified. For prevent GP from creating it each call to chrdx10() below. */
/* Global!*/ tmpv=vector(10001); \\ Up to 10000 digits.

chrdx10(operand1,operand2)={
    my(ans, focus=0, parser=operand1);
    while( (parser\operand2) > 0,
      tmpv[focus++]=(parser%operand2);
      parser\=operand2;
    );
    tmpv[focus++]=parser;
    ans=vector(focus,k,tmpv[focus-k+1]);
}

\\ Returns the decimal value when reading the vector "w" from left to right in base "u".

readrdx(w,u)=sum(k=1,#w,w[k]*u^(#w-k));

povolotsky_main()={
  print("Generating permutations for base r=",assumedBase,".");
  permutations(assumedBase);
  print("Ready for the pairs detection:");
  reportPovolotskyPairs();
  print("(END)");
  quit();
}

cano_main()={
  
  permutations(permutationsUpperBound);
  Q=vecsort(P);
  g=0;
  for(y=1,#Q-1,P[y]=((Q[y+1]-Q[y])/(assumedBase-1)); g+=(f=readrdx(chrdx10(P[y],assumedBase),10)); print(y," ",f," ",g," ",y+1));
  quit();
  
}

/* Call to one of the available "main" below */

cano_main();

/* End. */


/* Final note about povolotsky_main():
 ---------------------------------------

What would you see when running it ?... Let us say for example by specifing base 10...

 Base 10 or decimal has 7 <<pairs>> and the following output should be shown:
 
Generating permutations for base r=10.
Ready for the pairs detection:
        Loading permutations...
        Performing calculations...
        Reporting the pairs:
1) {7901234568,987654312};
2) {6913580247,864197523};
3) {4938271605,617283945};
4) {3950617284,493827156};
5) {1975308642,246913578};
6) {987654321,123456789};
7) {9876543210,1234567890};
(END)

 */